#include <buola/gui/cicon.h>
#include <buola/gui/cmenu.h>
#include <buola/gui/caccelerator.h>
#include <buola/os/cappmenu.h>
#include <buola/os/capplication.h>
#include <vector>

namespace buola { namespace gui {

CMenu::CMenu()
{
    mOpenFirstTime=false;
    mCachedCount=-1;
}

CMenu::~CMenu()
{
    for(int i=0;i<mItems.size();i++)
        mItems[i]->RemoveMenu(this);
}

PMenuItem CMenu::Get(int n)
{
    if(!mOpenFirstTime)
    {
        sFillMenu(this);
        mOpenFirstTime=true;
    }
    
    for(int i=0;i<mItems.size();i++)
    {
        if(mItems[i]->mType==CMenuItem::INLINE)
        {
            int lCount=mItems[i]->mSubMenu->size();
            if(n<lCount)
                return mItems[i]->mSubMenu->Get(n);
            else
                n-=lCount;
        }
        else
        {
            if(!n)
                return mItems[i];
            else
                n--;
        }
    }
    throw XNotFound("wrong index in CMenu::Get");
}

int CMenu::size()
{
    if(mCachedCount>=0) return mCachedCount;

    if(!mOpenFirstTime)
    {
        sFillMenu(this);
        mOpenFirstTime=true;
    }

    mCachedCount=0;

    for(int i=0;i<mItems.size();i++)
    {
        if(mItems[i]->mType==CMenuItem::INLINE)
        {
            mCachedCount+=mItems[i]->mSubMenu->size();
        }
        else
        {
            mCachedCount++;
        }
    }
    return mCachedCount;
}

PMenuItem CMenu::Add(PMenuItem pItem)
{
    mItems.push_back(pItem);

    mCachedCount=-1;

    if(pItem->IsInlineMenu())
    {
        pItem->GetSubMenu()->sChanged.Connect(&CMenu::OnInlineMenuChanged,this);
    }

    pItem->AddMenu(this);

    sChanged();

    return pItem;
}

void CMenu::AddTitle(const std::wstring &pText,PIcon pIcon)
{
    Add(new CMenuItem(CMenuItem::LABEL,pText,pIcon));
}

PMenu CMenu::AddSubMenu(const std::wstring &pText,PIcon pIcon,PMenu pSubMenu,
                            const std::wstring &pComment)
{
    return Add(new CMenuItem(CMenuItem::SUBMENU,pSubMenu,pText,pIcon,pComment))->GetSubMenu();
}

void CMenu::AddInlineMenu(PMenu pMenu)
{
    Add(new CMenuItem(CMenuItem::INLINE,pMenu));
}

void CMenu::AddSeparator()
{
    Add(new CMenuItem(CMenuItem::SEPARATOR));
}

void CMenu::AddWindow(const PWindow &pWindow)
{
    Add(new CMenuItem(CMenuItem::WINDOW,pWindow));
}

void CMenu::RemoveItem(PMenuItem pItem)
{
    mItems.erase(std::find(mItems.begin(),mItems.end(),pItem));

    mCachedCount=-1;

    sChanged();
}

void CMenu::RemoveAll()
{
    mItems.clear();

    mCachedCount=-1;

    sChanged();
}

void CMenu::FillWith(os::CAppMenu *pMenu)
{
    const std::vector<os::CAppMenu*> &lSubMenus=pMenu->GetSubMenus();
    
    for(int i=0;i<lSubMenus.size();i++)
    {
        if(lSubMenus[i]->empty()) continue;
        PMenu lSubMenu=new CMenu;
        lSubMenu->sFillMenu.Connect(&CMenu::FillWith,lSubMenu.get(),lSubMenus[i]);
        AddSubMenu(lSubMenus[i]->GetName(),CIcon::Get(lSubMenus[i]->GetIcon()),lSubMenu,lSubMenus[i]->GetComment());
    }

    const std::vector<os::CApplication*> &lApps=pMenu->GetApps();

    for(int i=0;i<lApps.size();i++)
    {
        Add(new_menu_item(lApps[i]->GetName(),lApps[i]->GetIcon(),nullptr,lApps[i]->GetComment()))->
                                                 eTriggered.Connect(&os::CApplication::Run,lApps[i]);
    }
}

void CMenu::OnItemChanged()
{
    sChanged();
}

void CMenu::OnInlineMenuChanged()
{
    mCachedCount=-1;
}

/*namespace gui*/ } /*namespace buola*/ }
